<?php
/**
 * @package DAO
 * @access  public
 * @filesource
 */
/**
 * Interface de onde todas as classes DAO devem implementar, garantindo que, ao
 * menos os quatro metodos estejam disponiveis para as classes de acesso aos
 * dados. Outros metodos podem ser criados, desde que nao interfiram no
 * funcionamento basico dos pre-existentes.
 */
abstract class DAO {
    /**
     * Metodo responsavel por incluir um registro na tabela especificada.
     * @access public
     * @param  array   $registro Contem os valores que serao inseridos na tabela.
     * @return integer Id do registro incluido.
     */
    public abstract static function inserir(Model $registro);

    /**
     * Metodo responsavel por alterar um registro na tabela especificada.
     * @access public
     * @param  array $registro Contem os valores que serao alterados na tabela.
     * Apenas os parametros informados serao alterados.  O único parametro
     * essencial e o que informa o Id do registro.
     * @return nothing
     */
    public abstract static function alterar(Model $registro);

    /**
     * Metodo responsavel por remover um registro na tabela especificada.
     * @access public
     * @param  integer $id Id do registro que sera removido.
     * @return bool    Verdadeiro quando o registro foi encontrado e removido.
     * Falso nos demais casos.
     */
    public abstract static function remover(Model $registro);

    /**
     * Metodo responsavel por consultar registros na tabela especificada.
     * @access public
     * @param  array $registro Contem os parametros que serao usados na
     * consulta.
     * @return array Registros encontrados.
     */
    public abstract static function consultar(Model $registro);

    /**
     * Atribui os paraetros da instruçao SQL usando os valores advindos do parametro $params.
     *
     * @param String $sql
     * @param Model|Array $params
     * @return String Instruçao SQL com os valores preenchidos.
     */
    public static function prepare($sql, $params) {
        $conn           = Conexao::obterConexao();
        $formatoCurto   = "(\d\d)[-\/](\d\d)[-\/](\d\d\d\d)";
        $formatoParcial = "$formatoCurto (\d\d):(\d\d):(\d\d)";
        $formatoLongo   = "$formatoCurto (\d\d):(\d\d):(\d\d)";

        if (is_object($params)) {
            $obj_vars = $params->get_object_vars();
            $keys     = array_keys($obj_vars);

            foreach ($keys as $key) {
                $value = $params->get($key);
                $param = ":$key";

                if (! is_array($value) && $value && ($value <> "null")) {
                    /*
                     * Verificamos a existencia de aspas anteriores.
                     */
                    if (! (preg_match("/'[%]{$param}[%]'/", $sql) || is_numeric($value))) {
                        if (is_object($value)) {
                            Functions::_debug($value);
                            continue;
                        }
                        if (preg_match("/^$formatoCurto$/", $value, $data)) {
                            /*
                             * Verificamos a existencia de uma data nos formatos:
                             * dd-mm-yyyy ou dd/mm/yyyy
                             */
                            $value = sprintf("%s-%s-%s", $data[3], $data[2], $data[1]);
                        } else if (preg_match("/^$formatoParcial$/", $value, $data)) {
                            /*
                             * Verificamos a existencia de uma data nos formatos:
                             * dd-mm-yyyy hh:mm:ss ou dd/mm/yyyy hh:mm
                             */
                            $value = sprintf("%s-%s-%s %s:%s:%s",
                                             $data[3], $data[2], $data[1],
                                             $data[4], $data[5], "00");
                        } else if (preg_match("/^$formatoLongo$/", $value, $data)) {
                            /*
                             * Verificamos a existencia de uma data nos formatos:
                             * dd-mm-yyyy hh:mm:ss ou dd/mm/yyyy hh:mm:ss
                             */
                            $value = sprintf("%s-%s-%s %s:%s:%s",
                                             $data[3], $data[2], $data[1],
                                             $data[4], $data[5], $data[6]);
                        } {
                            $value =  $conn->quote($value);
                        }
                    }
                } else {
                    $value = "null";
                }

                $sql = preg_replace("/($param)/i", $value, $sql);
            }
        }

        /*
         * Parametros nao utilizados sao silenciosamente eliminados.
         */
        $sql = preg_replace("/:\[a-zA-Z_\]*/", "null", $sql);

        return $sql;
    }

    /**
     * Atribui os parametros a consulta e a executa, retornando uma colecao de objetos do tipo indicado (parametro $class).
     *
     * @param String $sql
     * @param Model|Array $class Objeto descendente de Model ou vetor (utilizado pelo metodo prepare()) que contem os parametros que serao usados na consulta.
     * @return <type>
     */
    public static function query($sql, $class) {

        $conn = Conexao::obterConexao();
        $sql  = self::prepare($sql, $class);

        $stmt = $conn->query($sql, PDO::FETCH_CLASS, get_class($class));

        if ($stmt) {
            return $stmt->fetchAll();
        } else
            return null;

        return $stmt->fetchAll();
    }

    /**
     * Executa uma instrucao SQL determinada.
     *
     * @param String $sql
     * @param Model|Array $class Objeto descendente de Model ou vetor (utilizado pelo metodo prepare()) que contem os parametros que serao usados na consulta.
     * @return void
     */
    public static function exec($sql, Model $modelo) {

        $conn = Conexao::obterConexao();
        $sql  = self::prepare($sql, $modelo);
        return $conn->exec($sql);
    }

    public static function lastInsertedId() {
        /**
         * NOTA: Veja o motivo da construcao peculiar em:
         *       http://br.php.net/manual/en/pdo.lastinsertid.php
         */
        $conn        = Conexao::obterConexao();
        $sqlUltimoId = "select @@identity as lastInsertedId";
        $rs          = $conn->query($sqlUltimoId);
        $registro    = $rs->fetch();
    	
        return $registro["lastInsertedId"];
    }
    
}
?>